/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.rcs.adslmonitor;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.net.io.Util;
import org.apache.commons.net.telnet.EchoOptionHandler;
import org.apache.commons.net.telnet.SuppressGAOptionHandler;
import org.apache.commons.net.telnet.TelnetClient;
import org.apache.commons.net.telnet.TerminalTypeOptionHandler;
import org.rcs.adslmonitor.telnet.TelnetURLStreamHandlerFactory;

/**
 *
 * @author ruben
 */
public abstract class ADSLStatusFromTelnet extends ADSLStatus {

  static {
    URL.setURLStreamHandlerFactory(new TelnetURLStreamHandlerFactory());
  }
  private TelnetClient telnetClient = new TelnetClient();
  private InputStream reader;
  private PrintStream writer;

  private String closeCmd;
  private String promptLine;

  public ADSLStatusFromTelnet(String routerName, String promptLine, String closeCmd) {
    super(routerName);

    this.closeCmd = closeCmd;
    this.promptLine = promptLine;
  }

  protected void tryToConnect() throws Exception {
    URL url = getRouterURL();

    if (!telnetClient.isConnected()) {
//      telnetClient.addOptionHandler(new TerminalTypeOptionHandler("VT100", false, false, true, false));
//      telnetClient.addOptionHandler(new EchoOptionHandler(true, false, true, false));
//      telnetClient.addOptionHandler(new SuppressGAOptionHandler(true, true, true, true));
      
      telnetClient.connect(url.getHost(), url.getPort());

      reader = telnetClient.getInputStream();
      writer = new PrintStream(telnetClient.getOutputStream());
    }
  }

  protected void login() throws Exception {
    tryToConnect();

    String line = readUntil(':');

    if (line.isEmpty()) {
      throw new IOException("Can't login. No user request found");
    }

    writeText(getUser());

    line = readUntil(':');

    if (line.isEmpty()) {
      throw new IOException("Can't login. No password request found");
    }

    writeText(getPassword());
    writeText("");
    
    line = readLine();

    while (null != line && !line.contains(promptLine)) {
      line = readLine();
    }
  }

  protected void sendCommand(String command) throws IOException {
    writeText(command);
    readUntil('\r') ;
  }

  protected void sendCommand(String command, String... args) throws IOException {
    String fullCommand = command;

    for (String arg : args) {
      fullCommand += " " + arg;
    }

    sendCommand(fullCommand);
  }

  protected void close() throws IOException {
    sendCommand(closeCmd);
    telnetClient.disconnect();
  }

  protected String readLine() throws IOException {
    return readUntil('\n');
  }

  protected String readLineUntilPropmt() throws IOException {
    return readLineUntil(promptLine);
  }

  protected String readLineUntil(String txt) throws IOException {
    String result = null;
    String line = readLine();

    if (null != line && !line.contains(txt)) {
      result = line;
    }

    if (null != result)
      result = result.trim() ;
    
    return result;
  }

  protected String readUntil(char c) throws IOException {
    String result = null;
    int code = reader.read();
    boolean exit = -1 == code;

    if (!exit) {
      result = "";
    }

    while (!exit) {
      result += (char) code;

      code = reader.read();
      exit = -1 == code || (char) code == c;
    }

    return result;
  }

  protected void writeText(String text) {
    writeText(text, true);
  }

  protected void writeText(String text, boolean sendReturn) {
    if (sendReturn) {
      writer.println(text);
    } else {
      writer.print(text);
    }
    writer.flush();
  }

  @Override
  protected boolean onRefresh() {
    boolean result = false;

    try {
      login();
      result = onRefreshCmds();
      close();
    } catch (Exception ex) {
      setLastError(ex);
      result = false;
      Logger.getLogger(ADSLStatusFromTelnet.class.getName()).log(Level.SEVERE, null, ex);
    }

    return result;
  }

  protected abstract boolean onRefreshCmds();

  public static final void readWrite(final InputStream remoteInput,
          final OutputStream remoteOutput,
          final InputStream localInput,
          final OutputStream localOutput) {
    Thread reader, writer;

    reader = new Thread() {
      @Override
      public void run() {
        int ch;

        try {
          while (!interrupted() && (ch = localInput.read()) != -1) {
            remoteOutput.write(ch);
            remoteOutput.flush();
          }
        } catch (IOException e) {
          //e.printStackTrace();
        }
      }
    };

    writer = new Thread() {
      @Override
      public void run() {
        try {
          Util.copyStream(remoteInput, localOutput);
        } catch (IOException e) {
          e.printStackTrace();
          System.exit(1);
        }
      }
    };

    writer.setPriority(Thread.currentThread().getPriority() + 1);

    writer.start();
    reader.setDaemon(true);
    reader.start();

    try {
      writer.join();
      reader.interrupt();
    } catch (InterruptedException e) {
    }
  }

  public static void main(String[] args) {
    TelnetClient telnet;

    telnet = new TelnetClient();

    try {
      telnet.connect("192.168.1.1", 23);
    } catch (IOException e) {
      e.printStackTrace();
      System.exit(1);
    }

    readWrite(telnet.getInputStream(), telnet.getOutputStream(),
            System.in, System.out);

    try {
      telnet.disconnect();
    } catch (IOException e) {
      e.printStackTrace();
      System.exit(1);
    }

    System.exit(0);
  }

}
